import React, { useState, useRef, useEffect, useImperativeHandle, useMemo } from 'react';
import { Checkbox, Popover, Icon, Empty } from 'antd';
import RcTreeSelect from 'rc-tree-select';
import classNames from 'classnames';
import groupBy from 'lodash/groupBy';
import remove from 'lodash/remove';
import { array2Tree } from '@/utils/tree';
import { getIcons, renderSwitcherIcon } from './utils/iconUtil';
import styles from './style/index.module.less';
// import './style/components.less';

/**
 * 分组显示的树选择器
 * @param props
 * @constructor
 */
const TreeSelectGroup = React.forwardRef((props, ref) => {
    const {
        treeNodeLabelProp = 'title',
        renderCheckboxOption,
        renderTreeOptionTitle,
        data,
        value,
        onChange,
        className,
        size,
        bordered,
        dropdownClassName,
        treeCheckable = true,
        listHeight = 256,
        listItemHeight = 26,
        switcherIcon,
        treeLine,
        getPopupContainer,
        transitionName = 'slide-up',
        disabled,
        notFoundContent,
        treeNodeFilterProp = 'title',
        ...otherProps
    } = props;

    const selectRef = useRef(null);
    const treeData = useMemo(() => array2Tree(data), [data]);
    const [dropdownVisible, setDropdownVisible] = useState(false);
    const [selectedValue, setSelectedValue] = useState(value || []);
    const selectedValueRef = useRef(selectedValue);
    const groupedValue = useMemo(() => {
        if (value?.length) {
            return groupBy(
                data.filter(item => value.indexOf(item.id) > -1).sort((a, b) => value.indexOf(b) - value.indexOf(a)),
                'pId'
            );
        }
        return null;
    }, [data, value]);

    const prefixCls = 'ant4-select';
    const treePrefixCls = 'ant4-select-tree';
    const treeSelectPrefixCls = 'ant4-tree-select';
    const mergedClassName = classNames(
        styles.treeSelectGroup,
        treeSelectPrefixCls,
        {
            [`${prefixCls}-lg`]: size === 'large',
            [`${prefixCls}-sm`]: size === 'small',
            [`${prefixCls}-borderless`]: !bordered
        },
        className
    );

    const { suffixIcon, removeIcon, clearIcon } = getIcons({
        ...props,
        multiple: true,
        prefixCls
    });

    const mergedDropdownClassName = classNames(
        dropdownClassName,
        `${treeSelectPrefixCls}-dropdown`,
        styles.treeSelectDropdown
    );

    const displayTagClassName = classNames(styles.selectionItem, disabled && styles.selectionItemDisabled);

    useEffect(() => {
        setSelectedValue(value);
        selectedValueRef.current = value;
    }, [data, value]);

    // 阻止错误的 click 操作.
    // 因为有两个 popup, 只能弹出一个, 附加的弹层被点击的时候, 要组织下拉框显示
    const handlePreventWrongClick = e => {
        e.stopPropagation();
        // selectRef.current.blur();
    };

    const handleChange = val => {
        if (onChange) {
            onChange(val);
        }
    };

    // 下拉框显示
    const handleDropdownVisibleChange = open => {
        if (otherProps.onDropdownVisibleChange) {
            otherProps.onDropdownVisibleChange(open);
        }
        setDropdownVisible(open);
    };

    // 分组的 x 按钮. 选项选中的值
    const handleClose = checkedItems => {
        const result = [...selectedValueRef.current];
        checkedItems.forEach(val => {
            result.splice(
                result.findIndex(item => item === val),
                1
            );
        });
        if (onChange) {
            onChange(result);
        }
    };

    // 分组的复选框改变时, 增减具体项目
    const handleCheckboxGroupChange = (checkedValue, checkedItemIdInGroup) => {
        const result = [...selectedValue];
        // 先删除旧选项
        let targetIndex = -1; // 记住要插入的位置, 以免更新数据的时候排序出错
        checkedItemIdInGroup.forEach(val => {
            targetIndex = result.findIndex(item => item === val);
            if (targetIndex > -1) {
                result.splice(targetIndex, 1);
            }
        });
        // 在指定位置插入新数据
        if (targetIndex > -1 && checkedValue?.length) {
            checkedValue.forEach((item, m) => result.splice(targetIndex + m, 0, item));
        } else {
            checkedValue.forEach(item => result.push(item));
        }
        if (onChange) {
            onChange(result);
        }
    };

    // 分组的复选框改变时, 增减具体项目
    const handleCheckAllChange = (e, allItemInGroup) => {
        let result = [...selectedValue];
        if (e.target.checked) {
            const allItemInGroupIds = allItemInGroup.filter(item => !item.disabled).map(item => item.id);
            result = Array.from(new Set(result.concat(allItemInGroupIds)));
        } else {
            const allItemInGroupIds = allItemInGroup.map(item => item.id);
            remove(result, item => allItemInGroupIds.includes(item));
        }

        if (onChange) {
            onChange(result);
        }
    };

    // 重新渲染已选值的展示
    const tagRender = _props => {
        if (!groupedValue) {
            return null;
        }
        const { value: _value } = _props;
        const currentNode = data.filter(item => item.id === _value)?.[0];
        // 因为脏数据问题, 可能存在没有的数据, 直接把 value 当做 label返回
        if (!currentNode) {
            return (
                <div className={displayTagClassName}>
                    <span className={styles.selectionItemContent}>{_value}</span>
                    {!disabled ? (
                        <Icon
                            type="close"
                            className={styles.selectionItemRemove}
                            onClick={() => handleClose([_value])}
                        />
                    ) : null}
                </div>
            );
        }
        const currentParentNode = data.filter(item => item.id === currentNode.pId)?.[0];
        const groupedValueArray = Object.values(groupedValue);
        // 检查是不是被选中值的分组下面的第一个数据
        let isFirstItemInGroup = false;
        // eslint-disable-next-line no-plusplus
        for (let i = 0; i < groupedValueArray.length; i++) {
            const firstItem = groupedValueArray[i][0];
            if (firstItem?.id === _value) {
                isFirstItemInGroup = true;
                break;
            }
        }

        // render
        if (isFirstItemInGroup) {
            // 取得同级所有子节点
            const allItemInGroup = data
                .filter(item => item.pId === currentNode.pId)
                .map(item => ({
                    ...item,
                    label: item[treeNodeLabelProp]
                }));
            // @ts-ignore
            const checkedItemInGroup = groupedValue?.[currentNode.pId];
            const groupItem = data.find(item => item.id === currentNode.pId);
            const checkedItemIdInGroup = checkedItemInGroup.map(item => item.id);
            const displayTag = (
                <div className={displayTagClassName}>
                    <span className={styles.selectionItemContent}>{currentParentNode[treeNodeLabelProp]}</span>
                    <span className={styles.selectionItemCount}>
                        ({checkedItemInGroup.length}/{allItemInGroup.length})
                    </span>
                    {!disabled ? (
                        <Icon
                            type="close"
                            className={styles.selectionItemRemove}
                            onClick={() => handleClose(checkedItemIdInGroup)}
                        />
                    ) : null}
                </div>
            );
            return !dropdownVisible && !disabled ? (
                <span onMouseDown={handlePreventWrongClick}>
                    <Popover
                        // getPopupContainer={triggerNode => triggerNode.parentElement}
                        content={
                            <>
                                <div className={styles.popoverTitle}>
                                    <Checkbox
                                        indeterminate={allItemInGroup.length !== checkedItemIdInGroup.length}
                                        onChange={e => handleCheckAllChange(e, allItemInGroup)}
                                        checked={allItemInGroup.length === checkedItemIdInGroup.length}
                                        style={{ marginRight: '8px' }}
                                    />
                                    {groupItem?.title}
                                </div>
                                <Checkbox.Group
                                    className={styles.treeSelectGroupCheckboxGroup}
                                    value={checkedItemIdInGroup}
                                    disabled={disabled}
                                    onChange={checkedValue =>
                                        handleCheckboxGroupChange(checkedValue, checkedItemIdInGroup)
                                    }
                                >
                                    {allItemInGroup.map(item =>
                                        renderCheckboxOption ? (
                                            renderCheckboxOption(item)
                                        ) : (
                                            <Checkbox
                                                key={item.id}
                                                value={item.id}
                                                disabled={item.disabled}
                                                title={disabled && '无权限'}
                                            >
                                                {item.title}
                                            </Checkbox>
                                        )
                                    )}
                                </Checkbox.Group>
                            </>
                        }
                        placement="topLeft"
                    >
                        {displayTag}
                    </Popover>
                </span>
            ) : (
                displayTag
            );
        }
        return null;
    };

    const renderTreeOption = options =>
        options.map(item => (
            <RcTreeSelect.TreeNode
                key={item.id}
                value={item.id}
                title={renderTreeOptionTitle ? renderTreeOptionTitle(item) : item[treeNodeLabelProp]}
                label={item[treeNodeLabelProp]}
                checkable={item?.checkable}
                disableCheckbox={item?.disabled}
                selectable={item?.selectable}
                // disabled={item?.disabled}
                isLeaf={item?.isLeaf}
                className={styles.treeNode}
            >
                {item?.children?.length && renderTreeOption(item.children)}
            </RcTreeSelect.TreeNode>
        ));

    useImperativeHandle(ref, () => ({
        blur: () => {
            selectRef.current.blur();
        },
        focus: () => {
            selectRef.current.focus();
        }
    }));

    return (
        <div className={styles.treeSelectGroupWrap}>
            <RcTreeSelect
                ref={selectRef}
                virtual
                prefixCls={prefixCls}
                className={mergedClassName}
                listHeight={listHeight}
                listItemHeight={listItemHeight}
                treeCheckable={treeCheckable ? <span className={`${prefixCls}-tree-checkbox-inner`} /> : treeCheckable}
                multiple
                inputIcon={suffixIcon}
                removeIcon={removeIcon}
                clearIcon={clearIcon}
                switcherIcon={nodeProps => renderSwitcherIcon(treePrefixCls, switcherIcon, treeLine, nodeProps)}
                showTreeIcon={false}
                getPopupContainer={getPopupContainer}
                treeMotion={null}
                dropdownClassName={mergedDropdownClassName}
                transitionName={transitionName}
                value={selectedValue}
                treeNodeFilterProp={treeNodeFilterProp}
                tagRender={tagRender}
                onChange={handleChange}
                onDropdownVisibleChange={handleDropdownVisibleChange}
                style={{ width: '100%' }}
                dropdownStyle={{ maxHeight: 390, overflow: 'auto' }}
                treeDefaultExpandAll
                disabled={disabled}
                notFoundContent={<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
                placeholder="请选择"
                {...otherProps}
            >
                {renderTreeOption(treeData)}
            </RcTreeSelect>
        </div>
    );
});
TreeSelectGroup.displayName = 'TreeSelectGroup';

export default TreeSelectGroup;
